// 实现时间轮，通过类的构造和智能指针完成定时任务的执行
// 意义：通过时间轮可以更好的管理非活跃连接的销毁任务
// 提供功能：添加定时事件，取消定时事件，延时定时事件
#include <iostream>
#include <memory>
#include <functional>
#include <unordered_map>
#include <array>
#include <vector>
#include <unistd.h>

using timerFunc = std::function<void()>;
using delFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;            // 定时任务ID
    size_t _timeOut;       // 到期时间
    timerFunc _FuncCb; // 定时任务
    // delFunc _delCb;     // 用于释放时间轮中的weak_ptr, 避免内存泄露
    bool _isCancel;
public:
    TimerTask(const int id, const int timeout, const timerFunc& funcCb)
        :_id(id), _timeOut(timeout), _FuncCb(funcCb), _isCancel(false) {}
    // void setDelFunc(const delFunc& delCb){
    //     _delCb = delCb;
    // }
    size_t getDelayTime() { return _timeOut; }
    void cancelTask() { _isCancel = true; }
    ~TimerTask() {
        if (!_isCancel) _FuncCb();    // 只有没有删除，才需要执行任务
    }  // 析构时进行任务
};

template <size_t n>  // 非类型模板参数，通过定义其可以控制最大延迟时间
class TimeWheel      // 只有当所有shared_ptr全部被释放才会执行任务
{
    using ptrTask = std::shared_ptr<TimerTask>;
    using ptrWeak = std::weak_ptr<TimerTask>;
private:
    std::array<std::vector<ptrTask>, n> _wheel;
    std::unordered_map<uint64_t, ptrWeak> _idMap;    // 存储每个id对应任务的weak_ptr, 便于通过其构造出共享引用计数的shared_ptr
    size_t _tick;                                    // 当前指针指向的位置

public:
    TimeWheel() :_tick(0) {}
    bool addTimerTask(const uint64_t id, const uint32_t timeout, const timerFunc& funcCb)
    {
        if (_idMap.count(id)) return false;
        auto newTask = std::make_shared<TimerTask>(id, timeout, funcCb);
        size_t pos = (_tick + timeout - 1) % n;
        _wheel[pos].push_back(newTask);    // 在将要执行的位置添加任务
        _idMap[id] = newTask;
        return true;
    }
    bool delayTask(const int id)
    {
        if (!_idMap.count(id)) return false;
        if (_idMap[id].expired()) return false;
        auto ptrToTask = _idMap[id].lock();
        size_t outTime = ptrToTask->getDelayTime();
        size_t pos = (_tick + outTime) % n;
        _wheel[pos].push_back(std::move(ptrToTask));
        return true;
    }
    bool cancelTask(const int id)
    {  // 如果取消之后时间轮中还有取消的任务，那么无法添加相同id的任务
        if (!_idMap.count(id)) return false;
        if (_idMap[id].expired()) return false;
        auto ptrToTask = _idMap[id].lock();
        ptrToTask->cancelTask();
        ptrToTask.reset();   // 手动删除
        _idMap.erase(id);
        return true;
    }
    void wheelRun()
    {
        _wheel[_tick].clear();  // 将走过的位置里所有的shared_ptr清空
        _tick = (_tick + 1) % n;
    }
};


class Test
{
public:
    Test() { printf("构造！\n"); }
    ~Test() { printf("析构！\n"); }
    void close() { printf("执行任务!\n"); }
};

int main()
{
    std::shared_ptr<Test> t(new Test());
    TimeWheel<60> tw;
    tw.addTimerTask(1, 5, [t]() {t->close();});
    for (int i = 0; i < 5; ++i)
    {
        sleep(1);
        tw.wheelRun();
        std::cout << "------------------\n";
        if (i == 1) tw.delayTask(1), tw.cancelTask(1);
    }
    t.reset();
    std::shared_ptr<Test> t2(new Test());
    tw.addTimerTask(1, 5, [t2]() { t2->close(); });
    for (int i = 0;;)
    {
        sleep(1);
        tw.wheelRun();
        std::cout << "-------------------\n";
    }
    return 0;
}